﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using T.FAS.Runtime.Metadata.Entity;
using T.FAS.Runtime.Metadata.SPI;

namespace T.FAS.Runtime.Metadata.Dao
{
    public class MetaDataManagerHandlerCacheService<T>
    {
        private static readonly object s_lock = new object();
        public static bool IsCheckMetaTypeID = true;
        private static readonly Dictionary<string, T> s_cache = new Dictionary<string, T>();
        private static readonly Type s_type = typeof(MetaDataFactory);
        private static readonly Type s_curType = typeof(T);
        private static readonly MethodInfo s_methodInfo = s_type.GetMethods(BindingFlags.Public | BindingFlags.Static)
                                                .FirstOrDefault(t => t.ReturnType == typeof(T));
        private static List<MetaDataTypeInfo> s_metaDataTypeInfos;
        public static List<MetaDataTypeInfo> MetaDataTypeInfos
        {
            get
            {
                if (s_metaDataTypeInfos == null)
                {
                    s_metaDataTypeInfos = new MetaDataTypeInfoDao().GetMetaDataTypeInfos();
                }
                return s_metaDataTypeInfos;
            }
        }

        private static readonly List<Type> s_validTypes = new List<Type>
        {
            typeof(IMetaDataGenerateHandler),
            typeof(IMetaDataCompiler),
            typeof(IExtMetaDataManager),
            typeof(IMetaDataManager),
            typeof(IMetaDataContentHandler),
            typeof(IMetaDataReleaseManager),
            typeof(IMetaDataSerializer),
            typeof(IMetaDataExtPropertyHandler),
            typeof(IMetaDependencyHandler),
            typeof(IMetaDataTermHandler)
        };

        static MetaDataManagerHandlerCacheService() { }

        private MetaDataManagerHandlerCacheService() { }

        public static T Get(string metaTypeID)
        {
            if (string.IsNullOrEmpty(metaTypeID))
            {
                throw new ArgumentNullException(metaTypeID);
            }
            else if(IsCheckMetaTypeID && !MetaDataTypeInfos.Select(t => t.ID).Contains(metaTypeID))
            {
                throw new Exception($"不存在的元数据类型:{metaTypeID}");
            }
            if (!s_validTypes.Contains(s_curType))
            {
                throw new Exception($"不支持的manager接口类型");
            }
            try
            {
                if (s_cache.ContainsKey(metaTypeID)) return s_cache[metaTypeID];
                else
                {
                    lock (s_lock)
                    {
                        if (s_cache.ContainsKey(metaTypeID)) return s_cache[metaTypeID];
                        else
                        {
                            var val = (T)s_methodInfo.Invoke(null, new object[] { metaTypeID });
                            s_cache[metaTypeID] = val;
                            return val;
                        }
                    }
                }
            }
            catch (Exception e)
            {
                return default(T);
                throw new Exception($"获取元数据Manager缓存失败, msg:{e.Message}\r\n, e:{e}");
            }
        }
    }
}
